﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Web.Mvc;
using ControleRepresentante.Common;
using ControleRepresentante.Logic;
using ControleRepresentante.Logic.Models;
using Telerik.Web.Mvc.UI.Fluent;
using Attribute = ControleRepresentante.Logic.Models.Attribute;

namespace WebSite.ViewModels.IndexViewModels
{
    public class IndexColumnDefinitionsCollection
    {
        private readonly List<IIndexColumnDefinition> m_Columns;

        public IndexColumnDefinitionsCollection()
        {
            m_Columns = new List<IIndexColumnDefinition>();
        }

        public void Execute(IEnumerable<IndexColumn> indexColumns, GridColumnFactory<ModelBase> configurator, HtmlHelper htmlHelper)
        {
            foreach (IIndexColumnDefinition indexColumn in m_Columns)
            {
                if (indexColumn.ShouldShow(indexColumns))
                {
                    indexColumn.Execute(configurator, htmlHelper);
                }
            }
        }

        public void Register<T>(IndexColumn indexColumn, Func<ModelBase, HtmlHelper, T> template)
        {
            m_Columns.Add(new IndexColumnDefinition<T>(indexColumn, template));
        }

        public void Register<T>(IndexColumn indexColumn, Func<ModelBase, T> template)
        {
            m_Columns.Add(new IndexColumnDefinition<T>(indexColumn, template));
        }

        public bool ShouldShow(IndexColumn indexColumn)
        {
            return indexColumn.IsMandatory || !m_Columns.Any() || m_Columns.Any(x => x.IndexColumn == indexColumn);
        }

        public IEnumerable<IIndexColumnDefinition> GetIndexColumns()
        {
            return m_Columns;
        }
    }

    public interface IIndexColumnDefinition
    {
        bool ShouldShow(IEnumerable<IndexColumn> indexColumns);
        void Execute(GridColumnFactory<ModelBase> configurator, HtmlHelper htmlHelper);
        IndexColumn IndexColumn { get; }
        string Header { get; }
        string GetValue(ModelBase model, HtmlHelper htmlHelper);
    }

    public class IndexColumnDefinitionsCollectionWrapper<TModel>
        where TModel : ModelBase
    {
        private readonly IndexColumnDefinitionsCollection m_IndexColumnDefinitionsCollection;
        private readonly IIndexColumnsProvider m_IndexColumnsProvider;

        public IndexColumnDefinitionsCollectionWrapper(IndexColumnDefinitionsCollection indexColumnDefinitionsCollection, IIndexColumnsProvider indexColumnsProvider)
        {
            m_IndexColumnDefinitionsCollection = indexColumnDefinitionsCollection;
            m_IndexColumnsProvider = indexColumnsProvider;
        }

        public void Register<T>(Guid id, Func<TModel, HtmlHelper, T> template)
        {
            Func<ModelBase, HtmlHelper, T> innerTemplate = (m, h) => template((TModel) m, h);
            IndexColumn indexColumn = m_IndexColumnsProvider[id];
            m_IndexColumnDefinitionsCollection.Register(indexColumn, innerTemplate);
        }

        public void Register<T>(Attribute attribute, Func<TModel, T> template)
        {
            Func<ModelBase, T> innerTemplate = m => template((TModel) m);
            IndexColumn indexColumn = m_IndexColumnsProvider[attribute];
            m_IndexColumnDefinitionsCollection.Register(indexColumn, innerTemplate);
        }

        public void Register<T>(Guid id, Func<TModel, T> template)
        {
            Func<ModelBase, T> innerTemplate = m => template((TModel) m);
            IndexColumn indexColumn = m_IndexColumnsProvider[id];
            m_IndexColumnDefinitionsCollection.Register(indexColumn, innerTemplate);
        }
    }

    internal class IndexColumnDefinition<T> : IIndexColumnDefinition
    {
        private readonly Func<ModelBase, HtmlHelper, T> m_TemplateWithHtmlHelper;
        private readonly Func<ModelBase, T> m_Template;

        public IndexColumnDefinition(IndexColumn indexColumn, Func<ModelBase, HtmlHelper, T> templateWithHtmlHelper)
        {
            IndexColumn = indexColumn;
            m_TemplateWithHtmlHelper = templateWithHtmlHelper;
        }

        public IndexColumnDefinition(IndexColumn indexColumn, Func<ModelBase, T> template)
        {
            IndexColumn = indexColumn;
            m_Template = template;
        }

        public void Execute(GridColumnFactory<ModelBase> configurator, HtmlHelper htmlHelper)
        {
            configurator
                .Template(x => GetValue(x, htmlHelper))
                .HeaderTemplate(Header);
        }

        public string Header { get { return IndexColumn.Description; } }

        public string GetValue(ModelBase model, HtmlHelper htmlHelper)
        {
            T value = m_TemplateWithHtmlHelper == null ? m_Template(model) : m_TemplateWithHtmlHelper(model, htmlHelper);
            return value.FormatForDisplay();
        }

        public bool ShouldShow(IEnumerable<IndexColumn> indexColumns)
        {
            return indexColumns.Contains(IndexColumn);
        }

        public IndexColumn IndexColumn { get; private set; }
    }
}